Microprocessors perform computational operations on numerical values in a wide variety of applications. High execution speed, low power consumption and small size are important goals for processor designers, particularly in embedded applications such as portable electronic devices. Modern processors employ a pipelined architecture, where sequential instructions, each having multiple execution steps, are overlapped in execution. In a pipelined architecture, each instruction is executed in a series of execution stages, such as Fetch, Decode, Execute, and Write-Back, each of which may comprise a plurality of pipe stages. A pipe stage consists of a storage element and logic that executes all or part of an instruction execution stage. Instructions flow sequentially through the pipeline. The Execute stage performs the arithmetical, logical, or memory access operation specified by the instruction, and in particular may perform a variety of arithmetical operations on numerical values.
Digital processors represent numerical values in either fixed-point or floating-point format. A floating-point number comprises a fixed-point significand (also known as a mantissa) multiplied by the base 2 raised to an integer exponent. In some formats, such as the IEEE 754 standard, incorporated herein by reference, the floating-point representation additionally includes a sign bit. Multiplying the significand by 2 raised to an integer exponent is the binary analog to scientific notation in the base 10 system. That is, the value of the exponent determines the number of bit positions, and the direction, that the binary point in the significand should be shifted to realize the actual numerical value—hence the term, floating point.
When the significand is in the range 1<=significand<2 and the exponent is within its defined range, the floating-point value is referred to as a “normal” number. The significand of a normal floating-point number is thus of the form 1.fraction, where “fraction” is a binary value representing the fractional portion of the significand greater than one. The value of the exponent effectively shifts the binary point left (for a negative exponent) or right (for a positive exponent). In the IEEE 754 standard, the value of the exponent for a single-precision floating-point number ranges from −126 to 127. When encoding the number in IEEE 754 single-precision format, a bias of 127 is added to the raw exponent so that all encoded exponents are positive.
A floating-point value that is represented with a significand that is less than one, i.e., 0<significand<1, with any exponent, is referred to herein as an “unnormal” number. One subset of unnormal floating-point numbers of particular interest is “denormal” numbers (also known as subnormal numbers). Denormal floating-point numbers represent values smaller than 1.0×2−126 by utilizing a significand in the range 0<significand<1, and the exponent −126. A denormal floating-point number has a significand of the form 0.fraction, with the number of leading zeros in the fraction ranging from zero to the width of the fraction—1. A denormal number effectively utilizes bit positions in the fractional portion of a normal significand to achieve a “left shift” of the binary point in excess of 126 bit positions—at the cost of loss of precision, as fewer bits remain to accurately represent the numerical value. Denormal numbers represent values very close to zero, and may be used to implement gradual underflow, allowing a calculation to lose precision slowly when the result is very small.
In the case of a floating-point multiplier circuit, denormal products may arise in several ways. Either the multiplier or the multiplicand may be a denormal number. In this case the significand of the intermediate product will commonly be unnormal (i.e., less than one) while the final rounded product may be a normal or denormal number, depending on the numerical values of the operands. If both the multiplier and the multiplicand are denormal numbers, the final rounded product will be zero or the smallest representable denormal number.
Additionally, the product of two normal numbers may be a denormal number if the exponents are small and would yield a normalized number requiring an exponent less than −126 (for single-precision). Note that this case is distinct from the common situation in which an intermediate value of the multiplication assumes a “non-normal” form. A normal significand may assume any value in the range [1,2)—that is, from exactly one to almost two (1.0000 to 1.1111, for a hypothetical 5-bit significand). The product of two normal significands may assume a value in the range [1,4)—that is, from exactly one to almost four. This intermediate product significand thus may assume the form 1.fraction or 1x.fraction, the latter for values from two to almost four (10.0000 to 11.1111). Floating-point multipliers adjust this intermediate result by shifting the binary point left and incrementing the exponent by one, as a routine incident of floating-point multiplication. Such a “non-normal” intermediate result is not herein considered a denormal number, and is not explicitly addressed by the present disclosure.
In common processor applications, such as some embedded processors, denormal numbers need not always be supported. For example, denormal values may simply be represented as zero without significant loss of accuracy. However, the Java® programming language specifies support for denormal numbers. Accordingly, processors that support direct execution of Java code to accommodate denormal floating-point numbers, at least during a Java execution mode.
Denormal floating-point numbers may be supported in software by generating an exception upon detecting a denormal number, and processing the denormal number in a software routine. This process is slow and incurs a large degree of overhead, which reduces system performance and increases power consumption.
Denormal numbers may be supported in hardware by adding denormal detection and normalization circuits to each floating-point computational element. For example, denormal numbers may be “normalized” by shifting the significand to a normal position (i.e., 1.fraction), and allowing a (non-standard) value of the exponent smaller than −126 (for the single-precision case). Likewise, the results may be “denormalized” by shifting the significand to a denormal position (i.e., 0.fraction) so that the exponent becomes −126 (for the single precision case). However, such additional circuits increase silicon area, increase latency, and introduce throughput delay, potentially increasing the minimum cycle time and hence reducing the maximum operating frequency. Additionally, denormal numbers are rarely encountered, and optimizing performance for the rare case at the expense of the common case reduces overall processor performance.